package com.zzx.controller;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;

public class DayMain {
	/// 来源于网上的农历数据
    /// 数据年份从 1900 年开始，这个是计算机元年
    /// 数据结构如下，共使用17位数据
    /// 第17位：表示闰月天数，0表示29天   1表示30天
    /// 第16位-第5位（共12位）表示12个月，其中第16位表示第一月，如果该月为30天则为1，29天为0
    /// 第4位-第1位（共4位）表示闰月是哪个月，如果当年没有闰月，则置0
	 // 2019为例：0x0A930
	 // 0000 1010 1001 0011 0000
	 // 30 29 30 29 30 29 29  30 29 29 30 30 
	 //2018为例：0x052B0
	 // 0000 0101 0010 1011 0000
	 //2017 0x15176 润 6 月
	 // 0001 0101 0001 0111 0110
	 //      29 30 29 30 29 29 29 30 29 30 30 30 29 30 30 29
	 final private static long[] lunarInfo = new long[] { 0x04bd8, 0x04ae0,
			            0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0,
			            0x055d2, 0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540,
			            0x0d6a0, 0x0ada2, 0x095b0, 0x14977, 0x04970, 0x0a4b0, 0x0b4b5,
			            0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970,
			            0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3,
			            0x092e0, 0x1c8d7, 0x0c950, 0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0,
			            0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, 0x06ca0,
			            0x0b550, 0x15355, 0x04da0, 0x0a5d0, 0x14573, 0x052d0, 0x0a9a8,
			            0x0e950, 0x06aa0, 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570,
			            0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, 0x096d0, 0x04dd5,
			            0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b5a0,
			            0x195a6, 0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50,
			            0x06d40, 0x0af46, 0x0ab60, 0x09570, 0x04af5, 0x04970, 0x064b0,
			            0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0,
			            0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7,
			            0x025d0, 0x092d0, 0x0cab5, 0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50,
			            0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, 0x07954,
			            0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260,
			            0x0ea65, 0x0d530, 0x05aa0, 0x076a3, 0x096d0, 0x04bd7, 0x04ad0,
			            0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, 0x0b5a0, 0x056d0,
			            0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20,
			            0x0ada0 };
			    final private static int[] year20 = new int[] { 1, 4, 1, 2, 1, 2, 1, 1, 2,
			            1, 2, 1 };
			    final private static int[] year19 = new int[] { 0, 3, 0, 1, 0, 1, 0, 0, 1,
			            0, 1, 0 };
			    final private static int[] year2000 = new int[] { 0, 3, 1, 2, 1, 2, 1, 1,
			            2, 1, 2, 1 };
			    public final static String[] nStr1 = new String[] { "", "正", "二", "三", "四",
			            "五", "六", "七", "八", "九", "十", "冬月", "腊月" };
			    private final static String[] Gan = new String[] { "甲", "乙", "丙", "丁", "戊",
			            "己", "庚", "辛", "壬", "癸" };
			    private final static String[] Zhi = new String[] { "子", "丑", "寅", "卯", "辰",
			            "巳", "午", "未", "申", "酉", "戌", "亥" };
			    private final static String[] Animals = new String[] { "鼠", "牛", "虎", "兔",
			            "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪" };
			
			    private final static String[] solarTerm = new String[] { "小寒", "大寒", "立春",
			            "雨水", "惊蛰", "春分", "清明", "谷雨", "立夏", "小满", "芒种", "夏至", "小暑", "大暑",
			            "立秋", "处暑", "白露", "秋分", "寒露", "霜降", "立冬", "小雪", "大雪", "冬至" };
			    private final static String[] sFtv = new String[] { "0101*元旦", "0214 情人节",
			            "0308 妇女节", "0312 植树节", "0315 消费者权益日", "0401 愚人节", "0501 劳动节",
			            "0504 青年节", "0512 护士节", "0601 儿童节", "0701 建党节", "0801 建军节",
			            "0808 父亲节", "0909 mzd逝世纪念", "0910 教师节", "0928 孔子诞辰", "1001*国庆节",
			            "1006 老人节", "1024 联合国日", "1112 孙中山诞辰", "1220 澳门回归", "1225 圣诞节",
			            "1226 mzd诞辰" };
			    private final static String[] lFtv = new String[] { "0101*农历春节",
			            "0115 元宵节", "0505 端午节", "0707 七夕情人节", "0815 中秋节", "0909 重阳节",
			            "1208 腊八节", "1224 小年", "0100*除夕" };
			    private final static String[] gzArr = new String[] { 
			    		"甲子", "乙丑", "丙寅", "丁卯", "戊辰", "己巳", "庚午", "辛未", "壬申", "癸酉" ,
			    		"甲戌", "乙亥", "丙子", "丁丑", "戊寅", "己卯", "庚辰", "辛巳", "壬午", "癸未" ,
			    		"甲申", "乙酉", "丙戌", "丁亥", "戊子", "己丑", "庚寅", "辛卯", "壬辰", "癸巳" ,
			    		"甲午", "乙未", "丙申", "丁酉", "戊戌", "己亥", "庚子", "辛丑", "壬寅", "癸卯" ,
			    		"甲辰", "乙巳", "丙午", "丁未", "戊申", "己酉", "庚戌", "辛亥", "壬子", "癸丑" ,
			    		"甲寅", "乙卯", "丙辰", "丁巳", "戊午", "己未", "庚申", "辛酉", "壬戌", "癸亥" 
			            };
			    /**
			     * 传回农历 y年的总天数
			     * 
			     * @param y
			     * @return
			     */
			    final private static int lYearDays(int y) {
			        int i, sum = 348;//假设每个月都是 29天 12*29 = 348 天。
			        //0x0A930 数组里面的 十六进制 从5 - 16位 是月份大小标识。 0 29天 1 30天。
			        //0x8000 = 1000000000000000,从16位开始进行 & 操作。为真则是 大月，否则为小月。
			        for (i = 0x8000; i > 0x8; i >>= 1) {
			            if ((lunarInfo[y - 1900] & i) != 0)
			                sum += 1;
			        }
			        return (sum + leapDays(y));
			    }
			
			    /**
			     * 传回农历 y年闰月的天数
			     * 
			     * @param y
			     * @return
			     */
			    final private static int leapDays(int y) {
			        if (leapMonth(y) != 0) {//最后一位不等于0 则为改年有闰月。
			        	//第17位：表示闰月天数，0表示29天   1表示30天
			            if ((lunarInfo[y - 1900] & 0x10000) != 0)
			                return 30;
			            else
			                return 29;
			        } else
			            return 0;
			    }
			
			    /**
			     * 传回农历 y年闰哪个月 1-12 , 没闰传回 0
			     * 末四位与 1111 进行与操作，返回末四位的值。
			     * @param y
			     * @return
			     */
			    final private static int leapMonth(int y) {
			        return (int) (lunarInfo[y - 1900] & 0xf);
			    }
			
			    /**
			     * 传回农历 y年m月的总天数
			     * 
			     * @param y
			     * @param m
			     * @return
			     */
			    final private static int monthDays(int y, int m) {
			        if ((lunarInfo[y - 1900] & (0x10000 >> m)) == 0)
			            return 29;
			        else
			            return 30;
			    }
			
			    /**
			     * 传回农历 y年的生肖
			     * 
			     * @param y
			     * @return
			     */
			    final public static String AnimalsYear(int y) {
			        String rtnStr = Animals[(y-4)%12];
			    	return rtnStr;
			    }
			
			    /**
			     * 传入 月日的offset 传回干支,0=甲子
			     * 
			     * @param num
			     * @return
			     */
			    final private static String cyclicalm(int num) {
			        //第一种方法：年份 - 4 分别除以 10 和 12 得到对应干支，组合就是改年的干支。
			    	//第二种方法：年份 - 4 除以 60 得到的干支组合就是改年的干支。
			    	String rtnStr = gzArr[num%60];
			    	//String rtnStr = (Gan[num % 10] + Zhi[num % 12]);
			    	return rtnStr;
			    }
			
			    /**
			     * 传入 offset 传回干支, 0=甲子
			     * 
			     * @param y
			     * @return
			     */
			    final public static String cyclical(int y) {
			    	//拿当前年份随便减去一个甲子年，
			    	// 公元元年是辛酉 公元4年是甲子
			    	// 2019 - 3 结果：除以 10 余数为 天干、 除以12 余数为地支。
			        int num = y - 4;			     
			        return (cyclicalm(num));
			    }
			
			    /**
			     * 传出农历.year0 .month1 .day2 .yearCyl3 .monCyl4 .dayCyl5 .isLeap6
			     * 
			     * @param y
			     * @param m
			     * @return
			     */
			    final private long[] Lunar(int y, int m) {
			        long[] nongDate = new long[7];
			        int i = 0, temp = 0, leap = 0;
			        Date baseDate = new GregorianCalendar(1900 + 1900, 1, 31).getTime();
			        Date objDate = new GregorianCalendar(y + 1900, m, 1).getTime();
			        long offset = (objDate.getTime() - baseDate.getTime()) / 86400000L;
			        if (y < 2000)
			            offset += year19[m - 1];
			        if (y > 2000)
			            offset += year20[m - 1];
			        if (y == 2000)
			            offset += year2000[m - 1];
			        nongDate[5] = offset + 40;
			        nongDate[4] = 14;
			        for (i = 1900; i < 2050 && offset > 0; i++) {
			            temp = lYearDays(i);
			            offset -= temp;
			            nongDate[4] += 12;
			        }
			        if (offset < 0) {
			            offset += temp;
			            i--;
			            nongDate[4] -= 12;
			        }
			        nongDate[0] = i;
			        nongDate[3] = i - 1864;
			        leap = leapMonth(i); // 闰哪个月
			        nongDate[6] = 0;
			        for (i = 1; i < 13 && offset > 0; i++) {
			            // 闰月
			            if (leap > 0 && i == (leap + 1) && nongDate[6] == 0) {
			                --i;
			                nongDate[6] = 1;
			                temp = leapDays((int) nongDate[0]);
			            } else {
			                temp = monthDays((int) nongDate[0], i);
			            }
			            // 解除闰月
			            if (nongDate[6] == 1 && i == (leap + 1))
			                nongDate[6] = 0;
			            offset -= temp;
			            if (nongDate[6] == 0)
			                nongDate[4]++;
			        }
			        if (offset == 0 && leap > 0 && i == leap + 1) {
			            if (nongDate[6] == 1) {
			                nongDate[6] = 0;
			            } else {
			                nongDate[6] = 1;
			                --i;
			                --nongDate[4];
			            }
			        }
			        if (offset < 0) {
			            offset += temp;
			            --i;
			            --nongDate[4];
			        }
			        nongDate[1] = i;//得到yu
			        nongDate[2] = offset + 1;
			        return nongDate;
			    }
			
			    /**
			     * 传出y年m月d日对应的农历.year0 .month1 .day2 .yearCyl3 .monCyl4 .dayCyl5 .isLeap6
			     * 
			     * @param y
			     * @param m
			     * @param d
			     * @return
			     */
			    final public static long[] calElement(int y, int m, int d) {
			        long[] nongDate = new long[7];
			        int i = 0, temp = 0, leap = 0;
			        //计算机初始年份的时间
			        Date baseDate = new GregorianCalendar(0 + 1900, 0, 31).getTime();
			        //设置当前时间
			        Date objDate = new GregorianCalendar(y, m - 1, d).getTime();
			        //将当前时间 减去 计算机初始时间 除以 每天的毫秒数 得到总差值天数
			        long offset = (objDate.getTime() - baseDate.getTime()) / 86400000L;
			        nongDate[5] = offset + 40;//总天数 + 40天。
			        nongDate[4] = 14;
			        for (i = 1900; i < 2050 && offset > 0; i++) {
			            temp = lYearDays(i);//获取对应年的农历天数
			            offset -= temp;//
			            nongDate[4] += 12;
			        }
			        
			        if (offset < 0) {
			            offset += temp;
			            i--;
			            nongDate[4] -= 12;
			        }
			        nongDate[0] = i;//记录 年份 
			        nongDate[3] = i - 1864;
			        leap = leapMonth(i); // 闰哪个月
			        //System.err.println(i+" ** "+nongDate[4]+" * "+leap);
			        nongDate[6] = 0;
			        System.err.println("**11**"+offset);
			        for (i = 1; i < 13 && offset > 0; i++) {
			            // 闰月
			            if (leap > 0 && i == (leap + 1) && nongDate[6] == 0) {
			                --i;
			                nongDate[6] = 1;
			                temp = leapDays((int) nongDate[0]);
			            } else {
			                temp = monthDays((int) nongDate[0], i);//获取对应月份的天数
			            }
			            System.err.println("**22**"+temp);
			            // 解除闰月
			            if (nongDate[6] == 1 && i == (leap + 1))
			                nongDate[6] = 0;
			            offset -= temp;
			            if (nongDate[6] == 0)
			                nongDate[4]++;
			        }
			        if (offset == 0 && leap > 0 && i == leap + 1) {
			            if (nongDate[6] == 1) {
			                nongDate[6] = 0;
			            } else {
			                nongDate[6] = 1;
			                --i;
			                --nongDate[4];
			            }
			        }
			        if (offset < 0) {
			            offset += temp;
			            --i;
			            --nongDate[4];
			        }
			        System.err.println("****"+i);
			        nongDate[1] = i;
			        nongDate[2] = offset + 1;
			        return nongDate;
			    }
			
			    public final static String getChinaDate(int day) {
			        String a = "";
			        if (day == 10)
			            return "初十";
			        if (day == 20)
			            return "二十";
			        if (day == 30)
			            return "三十";
			        int two = (int) ((day) / 10);
			        if (two == 0)
			            a = "初";
			        if (two == 1)
			            a = "十";
			        if (two == 2)
			            a = "廿";
			        if (two == 3)
			            a = "三";
			        int one = (int) (day % 10);
			        switch (one) {
			        case 1:
			            a += "一";
			            break;
			        case 2:
			            a += "二";
			            break;
			        case 3:
			            a += "三";
			            break;
			        case 4:
			            a += "四";
			            break;
			        case 5:
			            a += "五";
			            break;
			        case 6:
			            a += "六";
			            break;
			        case 7:
			            a += "七";
			            break;
			        case 8:
			            a += "八";
			            break;
			        case 9:
			            a += "九";
			            break;
			        }
			        return a;
			    }
			    //获取今天的农历日期
			    public static String today() {
			        Calendar today = Calendar.getInstance(Locale.SIMPLIFIED_CHINESE);
			        int year = today.get(Calendar.YEAR);//当前年
			        int month = today.get(Calendar.MONTH) + 1;//当前月
			        int date = today.get(Calendar.DATE);//当前日
			        long[] l = calElement(year, month, date);
			        StringBuffer sToday = new StringBuffer();
			        try {
			            sToday.append(sdf.format(today.getTime()));
			            sToday.append(" 农历");
			            sToday.append(cyclical(year));//得到年份的干支
			            sToday.append('(');
			            sToday.append(AnimalsYear(year));//得到年份的十二生肖
			            sToday.append(")年");
			            //丙
			            sToday.append(nStr1[(int) l[1]]);
			            sToday.append("月");
			            sToday.append(getChinaDate((int) (l[2])));
			            return sToday.toString();
			        } finally {
			            sToday = null;
			        }
			    }
			    
			    public static String oneDay(int year,int month,int day) {
			        Calendar today = Calendar.getInstance(Locale.SIMPLIFIED_CHINESE);
			        long[] l = calElement(year, month, day);
			        StringBuffer sToday = new StringBuffer();
			        try {
			            sToday.append(sdf.format(today.getTime()));
			            sToday.append(" 农历");
			            sToday.append(cyclical(year));
			            sToday.append('(');
			            sToday.append(AnimalsYear(year));
			            sToday.append(")年");
			            sToday.append(nStr1[(int) l[1]]);
			            sToday.append("月");
			            sToday.append(getChinaDate((int) (l[2])));
			            return sToday.toString();
			        } finally {
			            sToday = null;
			        }
			    }
			
			    private static SimpleDateFormat sdf = new SimpleDateFormat(
			            "yyyy年M月d日 EEEEE");
			
			    /**
			      * 农历日历工具使用演示
			     * 
			     * @param args
			     */
			    public static void main(String[] args) {
			        System.out.println(today());
			        System.out.println(oneDay(1989, 9, 10));
			    }

}
